﻿using System;
using System.Runtime.InteropServices;
using System.Collections.ObjectModel;
using System.Windows;

namespace Silverlight.Windows
{
    [StructLayout(LayoutKind.Sequential)]
    internal struct Win32Rect
    {
        public int Left { get; set; }
        public int Top { get; set; }
        public int Right { get; set; }
        public int Bottom { get; set; }

        public override string ToString()
        {
            return string.Format("{0}, {1}, {2}, {3}", Left, Top, Right, Bottom);
        }
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct MonitorInfoEx
    {
        public int Size;
        public Win32Rect Monitor;
        public Win32Rect WorkArea;
        public uint Flags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DisplayMonitors.DeviceNameCharacterCount)]
        public string DeviceName;

        public void Init()
        {
            this.Size = 40 + 2 * DisplayMonitors.DeviceNameCharacterCount;
            this.DeviceName = string.Empty;
        }
    }

    internal static class DisplayMonitors
    {
        internal const int DeviceNameCharacterCount = 32;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi);

        [StructLayout(LayoutKind.Sequential)]
        internal struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator Point(POINT p)
            {
                return new Point(p.X, p.Y);
            }

            public static implicit operator POINT(Point p)
            {
                return new POINT((int ) p.X, (int )p.Y);
            }
        }

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags);

        private enum MonitorOptions : uint
        {
            MONITOR_DEFAULTTONULL = 0x00000000,
            MONITOR_DEFAULTTOPRIMARY = 0x00000001,
            MONITOR_DEFAULTTONEAREST = 0x00000002
        }

        internal static MonitorInfoEx GetMonitorInfoFromPoint(Point p)
        {
            var x = MonitorFromPoint(p,  MonitorOptions.MONITOR_DEFAULTTONEAREST);
            var monitor = new MonitorInfoEx();
            monitor.Init();
            GetMonitorInfo(x, ref monitor);
            return monitor;
        }
    }
}
